home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / biz / dopus / hotlistsource.lha / hotlist_source / source / hotlist.module.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-03  |  57.1 KB  |  1,772 lines

  1. /*######################################################################################
  2. ## hotlist.module by Leo 'Nudel' Davidson for Gods'Gift Utilities.                      ##
  3. ## A plug-in module for Directory Opus 5.5 to provide definable file/path hotlists.      ##
  4. ##                                                                                      ##
  5. ##                                                                                      ##
  6. ## Until July 1998 you should be able to contact me via any of the following:          ##
  7. ##                                                                                      ##
  8. ## email: leo.davidson@keble.oxford.ac.uk                                              ##
  9. ##   www: http://users.ox.ac.uk/~kebl0364                                              ##
  10. ##   IRC: Nudel in #Amiga on Effnet or Undernet (very rarely).                          ##
  11. ##                                                                                      ##
  12. ## Comments, suggestions, questions, offers, and chats all welcome.                      ##
  13. ##                                                                                      ##
  14. ##                                                                                      ##
  15. ## Tabsize: 4 -- 88 Columns (sorry) -- Amiga-specific -- Compile with SAS/C.          ##
  16. ##                                                                                      ##
  17. ## Credit is due to Nick Christie, Jonathan Potter, and Greg Perry for their advice,  ##
  18. ## examples, and general help beyond the call of duty. Thanks guys!                      ##
  19. ##************************************************************************************##
  20. ## There appears to be a bug in DOpus 5.5: Each call to AsyncRequestTags() looses      ##
  21. ## 32 bytes of memory. This also happens in the example module which comes with the      ##
  22. ## OpusSDK and has been reported to GPSoftware.                                          ##
  23. ########################################################################################
  24. ## This program never allocates more than about 30k at a time. Since all error          ##
  25. ## messages are output by requesters (which take quite a bit of mem to display),      ##
  26. ## memory allocation failures result in a silent abort. Perhaps it would be better      ##
  27. ## to at least call DisplayBeep() -- maybe in the future.                              ##
  28. ######################################################################################*/
  29.  
  30. #include "hotlist.module.h"
  31.  
  32. /**************************************************************************************/
  33.  
  34. #define PROGNAME "hotlist.module"
  35. #define PROGVERS "1.1" // When changing this, don't forget to update the values in
  36.                        // the makefile to keep things consistent.
  37. #define PROGDATE __AMIGADATE__
  38. static char version_str[] = "\0$VER: " PROGNAME " " PROGVERS " " PROGDATE "\0";
  39. // Above line should be double null-terminated.
  40.  
  41. /*= Definition of the module =========================================================*/
  42. ModuleInfo module_info =
  43. {
  44.         1,                                    // Version
  45.         "hotlist.module",                    // Module name
  46.         "hotlist.catalog",                    // Catalog name
  47.         0,                                    // Flags
  48.         1,                                    // Number of functions
  49.         {0,"Hotlist",MSG_HOTLIST_DESC,\
  50.          FUNCF_SINGLE_SOURCE|FUNCF_WANT_SOURCE,\
  51.          CMD_TEMPLATE}    // First (only) function.
  52. };
  53.  
  54. /*= Trapped Commands =================================================================*/
  55.  
  56. const char *trapCmds[] =
  57. {
  58.     "Delete","MakeDir","ScanDir",
  59.     "Hotlist","PrintDir","DiskInfo","Copy","CopyAs","Move","MoveAs","Rename","Parent",
  60.     "Root","Comment","Protect","Read","HexRead","Show","Play","Assign","GetSizes",
  61.     "DateStamp"
  62. };
  63. #define TRAPPEDNUM (sizeof(trapCmds)/sizeof(const char *))
  64.  
  65. /**************************************************************************************/
  66.  
  67. /*= L_Module_Entry() =================================================================-.
  68. || Main entry point to the module. The L_ is to identify this as a library              ||
  69. || function (specified by the "libprefix" option in the makefile)                      ||
  70. `-====================================================================================*/
  71. int __asm __saveds L_Module_Entry(
  72.     register __a0 char *args,                // User-supplied arguments
  73.     register __a1 struct Screen *screen,    // Screen to open on
  74.     register __a2 IPCData *ipc,                // Our IPC pointer
  75.     register __a3 IPCData *main_ipc,        // Main Opus IPC pointer
  76.     register __d0 ULONG mod_id,                // ID of module function
  77.     register __d1 EXT_FUNC(func_callback))    // Opus callback function
  78. {
  79.     Hotlist_Data *data;                // Pseudo-global variables.
  80.     FuncArgs *fa;
  81.     ResNode *combufrn;
  82.     struct command_packet cp;
  83.  
  84.     if (data = AllocVec(sizeof(Hotlist_Data),MEMF_CLEAR))
  85.     {
  86.         data->ipc = ipc;
  87.         data->func_callback = func_callback;
  88.  
  89.         if (data->rnd.poolhead = NewMemHandle(PUDDLESIZE,THRESHSIZE,MEMF_CLEAR))
  90.         {
  91.             data->rnd.data = data;
  92.  
  93.             // A separate pool is used for the linked list of hotlist-entries
  94.             // so that they can all be freed easily with one function call.
  95.             if (data->hentspool = NewMemHandle(HEPUDDLESIZE,HETHRESHSIZE,MEMF_CLEAR))
  96.             {
  97.                 if (DOpusBase->lib_Version < MIN_OPUS_VERSION)
  98.                     informUser(data,dgs(MSG_VERSREQ_FMT),FALSE,NULL,MIN_OPUS_VERSION);
  99.                 else if (addMsgPort(data))
  100.                 {
  101.                     fa = parseArgs(data,args);    // Parse command-line arguments.
  102.                     readConfigFile(data);        // Parse config file.
  103.  
  104.                     if (getListerHandle(data) && \
  105.                         (combufrn = allocNewResNode(&data->rnd,COMMBUFFSIZE)) )
  106.                     {
  107.                         basicListerInit(data,combufrn->rn_Mem,&cp);
  108.  
  109.                         // Now setup of lister is complete and we're waiting
  110.                         // for events from the user.
  111.  
  112.                         mainEventLoop(data,combufrn->rn_Mem,&cp);
  113.  
  114.                         // We are no longer the active handler for the lister,
  115.                         // time to exit.
  116.  
  117.                         deleteResNode(&data->rnd,combufrn);
  118.                     }
  119.                     freeArgs(fa);            // Free FuncArgs structure, if any.
  120.                     remMsgPort(data);
  121.                 }
  122.                 FreeMemHandle(data->hentspool);
  123.                 data->hentspool = NULL;
  124.             }
  125.             // Make sure all ResourceNodes and contents freed in case of an abort.
  126.             deleteAllResNodes(&data->rnd);    // Safe to call even if no ResNodes.
  127.             // Free our memory pool.
  128.             FreeMemHandle(data->rnd.poolhead);
  129.             data->rnd.poolhead = NULL;
  130.         }
  131.         // Free out pseudo-global variables.
  132.         FreeVec(data);
  133.     }
  134.     // Currently, functions should always return 1.
  135.     return(1);
  136. }
  137.  
  138. /*= InformUser() =====================================================================-.
  139. || Send the user a requester with printf-style formatted text.                          ||
  140. || Requester is centered on the Opus screen and has just an "OK" gadget.              ||
  141. || If window is TRUE it'll try to open over the lister window.                          ||
  142. ||------------------------------------------------------------------------------------||
  143. || Flags: IU_CANCEL - Adds a "Cancel" button as well as "OK". Returns boolean.          ||
  144. `-====================================================================================*/
  145. long informUser(Hotlist_Data *data,char *format,BOOL window,ULONG flags,...)
  146. {
  147.     long iu_return = 0;
  148.     struct Window *win;
  149.     struct Screen *screen;
  150.     ResNode *rn1;
  151.     va_list  ap;
  152.  
  153.     if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
  154.     {
  155.         // Build requester text
  156.         va_start(ap,flags);
  157.         vsprintf(rn1->rn_Mem,format,ap);
  158.         va_end(ap);
  159.  
  160.         if (window)
  161.         {
  162.             win = getListerWindow(data);
  163.             screen = NULL;
  164.         }
  165.         else
  166.         {
  167.             screen = getDOpusScreen(data);
  168.             win = NULL;
  169.         }
  170.  
  171.         // Display requester over window.
  172.         iu_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
  173.             TAGIF(win,AR_Window),    win,
  174.             TAGIF((!win) && screen,AR_Screen),    screen,
  175.             AR_Message,                rn1->rn_Mem,
  176.             AR_Title,                dgs(MSG_TITLE),
  177.             AR_Button,                dgs(MSG_OK_GAD),
  178.             TAGIF(flags & IU_CANCEL,AR_Button), dgs(MSG_CANCEL_GAD),
  179.             TAG_END);
  180.  
  181.         deleteResNode(&data->rnd,rn1);
  182.     }
  183.     return(iu_return);
  184. }
  185.  
  186. /*= GetString() ======================================================================-.
  187. || Send the user a string requester with printf-style formatted text.                  ||
  188. || Centred on the Opus screen unless win is TRUE.                                      ||
  189. || strbuff is the buffer to put the string into, bufflen its size.                      ||
  190. || Returns the number of the button they pressed (1 for "OK", 0 for "Cancel").          ||
  191. ||------------------------------------------------------------------------------------||
  192. || Flags: As for dopus5.library/AsyncRequest()                                          ||
  193. `-====================================================================================*/
  194. long getString(Hotlist_Data *data,char *format,BOOL window,ULONG flags,\
  195.                 char *strbuff,long bufflen,...)
  196. {
  197.     long gs_return = 0;
  198.     struct Window *win;
  199.     struct Screen *screen;
  200.     ResNode *rn1;
  201.     va_list  ap;
  202.  
  203.     if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
  204.     {
  205.         // Build requester text
  206.         va_start(ap,bufflen);
  207.         vsprintf(rn1->rn_Mem,format,ap);
  208.         va_end(ap);
  209.  
  210.         if (window)
  211.         {
  212.             win = getListerWindow(data);
  213.             screen = NULL;
  214.         }
  215.         else
  216.         {
  217.             screen = getDOpusScreen(data);
  218.             win = NULL;
  219.         }
  220.  
  221.         // Display requester over window.
  222.         gs_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
  223.             TAGIF(win,AR_Window),    win,
  224.             TAGIF((!win) && screen,AR_Screen),    screen,
  225.             AR_Message,                rn1->rn_Mem,
  226.             AR_Title,                dgs(MSG_TITLE),
  227.             AR_Button,                dgs(MSG_OK_GAD),
  228.             AR_Button,                dgs(MSG_CANCEL_GAD),
  229.             AR_Buffer,                strbuff,
  230.             AR_BufLen,                bufflen,
  231.             AR_Flags,                flags,
  232.             TAG_END);
  233.  
  234.         deleteResNode(&data->rnd,rn1);
  235.     }
  236.     return(gs_return);
  237. }
  238.  
  239. /*= GetPathString() ==================================================================-.
  240. || Send the user a string requester with printf-style formatted text.                  ||
  241. || This requester will also have a "Browse" button which replaces the string          ||
  242. || requester with a file requester (transparent to caller -- it will be as if they      ||
  243. || typed the selected path into the string requester, or canceled it if they cancel). ||
  244. || Centred on the Opus screen unless win is TRUE.                                      ||
  245. || strbuff is the buffer to put the string into, bufflen its size.                      ||
  246. || Returns the number of the button they pressed (1 for "OK", 0 for "Cancel").          ||
  247. ||------------------------------------------------------------------------------------||
  248. || Flags: As for dopus5.library/AsyncRequest()                                          ||
  249. `-====================================================================================*/
  250. long getPathString(Hotlist_Data *data,char *format,BOOL window,ULONG flags,\
  251.                 char *strbuff,long bufflen,...)
  252. {
  253.     long gs_return = 0;
  254.     struct Window *win;
  255.     struct Screen *screen;
  256.     ResNode *rn1;
  257.     va_list  ap;
  258.     APTR req;
  259.     char *fpath;
  260.  
  261.     if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
  262.     {
  263.         // Build requester text
  264.         va_start(ap,bufflen);
  265.         vsprintf(rn1->rn_Mem,format,ap);
  266.         va_end(ap);
  267.  
  268.         if (window)
  269.         {
  270.             win = getListerWindow(data);
  271.             screen = NULL;
  272.         }
  273.         else
  274.         {
  275.             screen = getDOpusScreen(data);
  276.             win = NULL;
  277.         }
  278.  
  279.         // Display requester over window.
  280.         gs_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
  281.             TAGIF(win,AR_Window),    win,
  282.             TAGIF((!win) && screen,AR_Screen),    screen,
  283.             AR_Message,                rn1->rn_Mem,
  284.             AR_Title,                dgs(MSG_TITLE),
  285.             AR_Button,                dgs(MSG_OK_GAD),
  286.             AR_Button,                dgs(MSG_BROWSE_GAD),
  287.             AR_Button,                dgs(MSG_CANCEL_GAD),
  288.             AR_Buffer,                strbuff,
  289.             AR_BufLen,                bufflen,
  290.             AR_Flags,                flags,
  291.             TAG_END);
  292.  
  293.         // If they selected "browse":
  294.         if (gs_return == 2)
  295.         {
  296.             gs_return = 0;
  297.  
  298.             if (req = AllocAslRequestTags(ASL_FileRequest,
  299.                         TAGIF(win,ASLFR_Window),    win,
  300.                         TAGIF((!win) && screen,ASLFR_Screen),    screen,
  301.                         ASLFR_InitialDrawer,        "SYS:",
  302.                         TAG_END))
  303.             {
  304.                 if (gs_return = AslRequestTags(req,TAG_END))
  305.                 {
  306.                     fpath = stpcpy(strbuff,((struct FileRequester *)req)->fr_Drawer);
  307.  
  308.                     // If there was a path string and it didn't end in "/" or ":",
  309.                     // insert a "/" before the filename.
  310.  
  311.                     if ( (((struct FileRequester *)req)->fr_Drawer[0]) && \
  312.                          (fpath[-1] != ':') && (fpath[-1] != '/') )
  313.                     {
  314.                         fpath = stpcpy(fpath,"/");
  315.                     }
  316.                     stpcpy(fpath,((struct FileRequester *)req)->fr_File);
  317.                 }
  318.                 FreeAslRequest(req);
  319.             }
  320.         }
  321.  
  322.         deleteResNode(&data->rnd,rn1);
  323.     }
  324.     return(gs_return);
  325. }
  326.  
  327. /*= getListerHandle() ================================================================-.
  328. || Fills in data->lister & data->listerhandle with handle of the lister we're to use. ||
  329. || If there is no source lister, or the NEW argument was given, a new lister is          ||
  330. || transparently created.                                                              ||
  331. || data->parent will be set to the path of the old lister, or to the empty string if  ||
  332. || a new lister was created or the path was unobtainable.                              ||
  333. || Returns boolean success.                                                              ||
  334. `-====================================================================================*/
  335. BOOL getListerHandle(Hotlist_Data *data)
  336. {
  337.     BOOL glh_return = FALSE;
  338.     ResNode *combufrn;
  339.     struct command_packet cp;
  340.  
  341.     (data->lister)[0] = '\0';    // Make sure it's empty because we'll use it to
  342.                                 // check if we got a souce lister or not.
  343.  
  344.     (data->parent)[0] = '\0';    // Set this to the empty string by default.
  345.  
  346.     // Allocate a command buffer.
  347.     if (combufrn = allocNewResNode(&data->rnd,COMMBUFFSIZE))
  348.     {
  349.         struct path_node *pn;
  350.  
  351.         // If they didn't give the "NEW" switch, first attempt to get the
  352.         // source lister.
  353.         if (!(data->new))
  354.         {
  355.             // Killing two birds with one stone, get the old path into data->parent
  356.             // and get a pointer to the structure with the wanted lister handle, too.
  357.             // If the lister handle is NULL, we'll have to get a new one (this will
  358.             // if they press run us from the toolbar of a devicelist lister).
  359.             if ((pn = (struct path_node *)data->func_callback(EXTCMD_GET_SOURCE,\
  360.                                             IPCDATA(data->ipc),data->parent)) && \
  361.                 (pn->lister))
  362.             {
  363.                 glh_return = TRUE;        // We got one! -- Convert long to ASCII.
  364.                 stcl_d(data->lister,(long)(pn->lister));
  365.             }
  366.         }
  367.  
  368. // If any source listers are locked now, unlock them. (Even if we're going to
  369. // use one of the source listers as it'll be made busy again shortly).
  370.  
  371.         data->func_callback(EXTCMD_UNLOCK_SOURCE,IPCDATA(data->ipc),NULL);
  372.  
  373.  
  374.         // If there still isn't a lister handle, either "NEW" was given or we
  375.         // couldn't get a source lister, so open a new one.
  376.         if ((data->lister)[0] == '\0')
  377.         {
  378.             // Just incase it was wrongly set TRUE in the get-source part.
  379.             glh_return = FALSE;
  380.  
  381.             // "lister new" command string, with or without snapshot geometry.
  382.             if ( ((data->snap.x) == (-1)) && ((data->snap.y) == (-1)) && \
  383.                  ((data->snap.w) == (-1)) && ((data->snap.h) == (-1)) )
  384.             {
  385.                 cp.command = "lister new";
  386.             }
  387.             else
  388.             {
  389.                 sprintf(combufrn->rn_Mem,"lister new %d/%d/%d/%d",
  390.                     data->snap.x,data->snap.y,data->snap.w,data->snap.h);
  391.                 cp.command = combufrn->rn_Mem;
  392.             }
  393.             cp.flags = COMMANDF_RESULT;            // We do want a result.
  394.             // Send the command.
  395.             if ( (data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),&cp)) && \
  396.                  ((cp.rc) == 0) && (cp.result) && (*(cp.result)) )
  397.             {
  398.                 strcpy(data->lister,cp.result);        // Store the handle string.
  399.                 FreeVec(cp.result);                    // Free the result string's mem.
  400.                 glh_return = TRUE;                    // We got one!
  401.             }
  402.         }
  403.  
  404.         deleteResNode(&data->rnd,combufrn);
  405.     }
  406.  
  407.     if (glh_return)
  408.     {
  409.         // If we got a lister handle in the end, store an APTR version of it, too.
  410.         (data->listerhandle) = (APTR)(atol(data->lister));
  411.     }
  412.  
  413.     return(glh_return);
  414. }
  415.  
  416. /*= sendExtCmd_nr() ==================================================================-.
  417. || Function to make calling Opus ARexx commands slightly cleaner. This version for      ||
  418. || when you do not want a result string.                                              ||
  419. `-====================================================================================*/
  420. void sendExtCmd_nr(Hotlist_Data *data,char *cmdstring,struct command_packet *cpp)
  421. {
  422.     // We do NOT want a result, but dopus5.library seems prone to
  423.     // memory leaks when one isn't requested for certain commands,
  424.     // so we'll ask for one and free it immediately afterwards.
  425.     cpp->flags = COMMANDF_RESULT;
  426.     cpp->command = cmdstring;
  427.     data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
  428.     FreeVec(cpp->result);
  429.     cpp->result = NULL;
  430. }
  431.  
  432. /*= addEntries() =====================================================================-.
  433. || Add the entries in the linked list of HotEntry structures to the lister.              ||
  434. || Does not refresh the lister.                                                          ||
  435. `-====================================================================================*/
  436. void addEntries(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
  437. {
  438.     HotEntry *hep;
  439.  
  440.     if (data->hentbase)
  441.     {
  442.         for (hep = data->hentbase; hep; hep = hep->next)
  443.         {
  444.             // We do NOT want a result, but dopus5.library seems prone to
  445.             // memory leaks when one isn't requested for certain commands,
  446.             // so we'll ask for one and free it immediately afterwards.
  447.             // (Haven't used sendExtCmd_nr for some extra speed here.)
  448.             cpp->flags = COMMANDF_RESULT;
  449.             cpp->command = combuf;
  450.             sprintf(combuf,"lister add %s \"%s\" 0 %d 0 rwed (%s)",
  451.                 data->lister,hep->name,hep->type,hep->path);
  452.             data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
  453.             FreeVec(cpp->result);
  454.             cpp->result = NULL;
  455.         }
  456.     }
  457.     else
  458.     {
  459.         // Otherwise add a default entry saying "Empty: drop here" type thing.
  460.         sprintf(combuf,"lister add %s \"%s\" 0 %d 0 rwed (%s)",
  461.                 data->lister,dgs(MSG_DEFAULTNAME),-2,dgs(MSG_DEFAULTPATH));
  462.         sendExtCmd_nr(data,combuf,cpp);
  463.     }
  464. }
  465.  
  466. /*= mainEventLoop() ==================================================================-.
  467. || Once the lister is setup, this loops around until an inactive event, dealing with  ||
  468. || the events the user throws at it.                                                  ||
  469. `-====================================================================================*/
  470. void mainEventLoop(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
  471. {
  472.     struct StandardPacket *pkt;
  473.     BOOL stoploop = FALSE;
  474.     char *a0;
  475.     char *a1;
  476.     char *a2;
  477.     char *a3;
  478.     char *a4;
  479.     char *a5;
  480.     char *a6;
  481.  
  482.     while(TRUE)
  483.     {
  484.         WaitPort(data->msgport);
  485.         while ((!stoploop) && (pkt = (struct StandardPacket *)GetMsg(data->msgport)))
  486.         {
  487.             // Note that the arg?'s start from 0 to be in sync with Opus ARexx Guide.
  488.             a0 = (char *)pkt->sp_Pkt.dp_Arg1;
  489.             a1 = (char *)pkt->sp_Pkt.dp_Arg2;
  490.             a2 = (char *)pkt->sp_Pkt.dp_Arg3;
  491.             a3 = (char *)pkt->sp_Pkt.dp_Arg4;
  492.             a4 = (char *)pkt->sp_Pkt.dp_Arg5;
  493.             a5 = (char *)pkt->sp_Pkt.dp_Arg6;
  494.             a6 = (char *)pkt->sp_Pkt.dp_Arg7;
  495. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  496.             if (strcmp(a0,"inactive") == 0)
  497.             {
  498.                 stoploop = event_inactive(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  499.             }
  500.             else if (strcmp(a0,"doubleclick") == 0)
  501.             {
  502.                 stoploop = event_doubleclick(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  503.             }
  504.             else if (strcmp(a0,"dropfrom") == 0)
  505.             {
  506.                 stoploop = event_dropfrom(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  507.             }
  508.             else if (strcmp(a0,"drop") == 0)
  509.             {
  510.                 stoploop = event_drop(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  511.             }
  512.             else if (strcmp(a0,"MakeDir") == 0)
  513.             {
  514.                 stoploop = event_makedir(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  515.             }
  516.             else if (strcmp(a0,"Delete") == 0)
  517.             {
  518.                 stoploop = event_delete(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  519.             }
  520.             else if (strcmp(a0,"path") == 0)
  521.             {
  522.                 stoploop = event_path(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  523.             }
  524.             else if ((strcmp(a0,"ScanDir") == 0) || (strcmp(a0,"Hotlist") == 0))
  525.             {
  526.                 stoploop = event_scandir_hotlist(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  527.             }
  528.             else if (strcmp(a0,"snapshot") == 0)
  529.             {
  530.                 stoploop = event_snapshot(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  531.             }
  532.             else if (strcmp(a0,"unsnapshot") == 0)
  533.             {
  534.                 stoploop = event_unsnapshot(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  535.             }
  536.             else if (strcmp(a0,"Rename") == 0)
  537.             {
  538.                 stoploop = event_rename(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  539.             }
  540.             else if (strcmp(a0,"parent") == 0)
  541.             {
  542.                 stoploop = event_parent(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
  543.             }
  544.             else
  545.             {
  546.                 sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  547.                 sendExtCmd_nr(data,combuf,cpp);
  548.                 informUser(data,dgs(MSG_UNSUPPORTED_FMT),TRUE,0,a0);
  549.                 sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  550.                 sendExtCmd_nr(data,combuf,cpp);
  551.             }
  552. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  553.             ReplyMsg((struct Message *)pkt);
  554.         }
  555.         if (stoploop) break;
  556.     }
  557. }
  558.  
  559. /*= writeConfigFile() ================================================================-.
  560. || Attempts to write the current entry data to the config file. If anything fails an  ||
  561. || error requester will probably be shown to the user, but there is no return result; ||
  562. || the rest of the program should continue even if the config file couldn't be          ||
  563. || written.                                                                              ||
  564. `-====================================================================================*/
  565. void writeConfigFile(Hotlist_Data *data)
  566. {
  567.     BOOL ifffailed = FALSE;
  568.     HotEntry *hent;
  569.     APTR iffhandle;
  570.     int confver;
  571.  
  572.     confver = CONFIGVER;
  573.  
  574. // Even if there are no hotlist entries, we should still write the config file
  575. // because it also contains snapshot information (and maybe more in the future).
  576.  
  577.     if (iffhandle = IFFOpen(data->config,IFF_WRITE|IFF_SAFE,ID_DOHL))
  578.     {
  579.         if ( (!(IFFWriteChunk(iffhandle,&confver,ID_VERS,sizeof(int)))) || \
  580.              (!(IFFWriteChunk(iffhandle,&data->snap,ID_SNAP,sizeof(data->snap)))) || \
  581.              (!(IFFWriteChunk(iffhandle,&data->time,ID_TIME,sizeof(data->time)))) )
  582.             ifffailed = TRUE;
  583.  
  584.         for (hent = data->hentbase; (!ifffailed) && hent; hent = hent->next)
  585.         {
  586.             // Only save the entry if it hasn't been marked for deletion.
  587.             if (!(hent->deleted))
  588.             {
  589.                 // The NAME field must always be first as it is used when reading
  590.                 // the config file to designate the start of each new entry.
  591.                 if ((!IFFWriteChunk(iffhandle,hent->name,ID_NAME,strlen(hent->name)+1))\
  592.                  || (!IFFWriteChunk(iffhandle,hent->path,ID_PATH,strlen(hent->path)+1))\
  593.                  || (!IFFWriteChunk(iffhandle,&hent->type,ID_TYPE,sizeof(hent->type))) )
  594.                 {
  595.                     ifffailed = TRUE;
  596.                 }
  597.             }
  598.         }
  599.  
  600.         if (ifffailed)
  601.         {
  602.             informUser(data,dgs(MSG_CONFIGWRITE_ERROR),TRUE,NULL);
  603.             IFFFailure(iffhandle);
  604.         }
  605.  
  606.         IFFClose(iffhandle);
  607.     }
  608. }
  609.  
  610. /*= readConfigFile() =================================================================-.
  611. || Attempts to replace the existing config (if any) in memory with that stored in the ||
  612. || config file.                                                                          ||
  613. || If the config file could not be read, hentbase will be NULL and the snapshot          ||
  614. || position will be disabled (all -1). This will happen when the user hasn't yet      ||
  615. || made a hotlist, for example, as well as when there is a genuine error.              ||
  616. `-====================================================================================*/
  617. void readConfigFile(Hotlist_Data *data)
  618. {
  619.     BOOL iffsucc;
  620.     HotEntry *chent;
  621.     ULONG chunkid;
  622.     APTR iffhandle;
  623.     struct ClockData newtime;
  624.     ULONG tsecs;
  625.     ULONG tmics;
  626.  
  627.     iffsucc = FALSE;
  628.  
  629.     CurrentTime(&tsecs,&tmics);
  630.     Amiga2Date(tsecs,&newtime);
  631.  
  632.     // Default geometry for new lister. -1 for all means "not snapshotted".
  633.     data->snap.x = data->snap.y = data->snap.w = data->snap.h = -1;
  634.  
  635.     data->time.sec   = newtime.sec;
  636.     data->time.min   = newtime.min;
  637.     data->time.hour  = newtime.hour;
  638.     data->time.mday  = newtime.mday;
  639.     data->time.month = newtime.month;
  640.     data->time.year  = newtime.year;
  641.     data->time.wday  = newtime.wday;
  642.  
  643.     if (iffhandle = IFFOpen(data->config,IFF_READ,ID_DOHL))
  644.     {
  645.         iffsucc = TRUE;
  646.         chent = NULL;
  647.         while ((iffsucc) && (chunkid = IFFNextChunk(iffhandle,0)))
  648.         {
  649.             // The NAME chunk designates a new hotlist entry.
  650.             if ((chunkid == ID_NAME) && (chent = newHotEntry(data)))
  651.                 iffsucc = IFFReadChunkBytes(iffhandle,chent->name,sizeof(chent->name));
  652.             else if ((chent) && (chunkid == ID_PATH))
  653.                 iffsucc = IFFReadChunkBytes(iffhandle,chent->path,sizeof(chent->path));
  654.             else if ((chent) && (chunkid == ID_TYPE))
  655.                 iffsucc = IFFReadChunkBytes(iffhandle,&chent->type,sizeof(chent->type));
  656.             else if (chunkid == ID_SNAP)
  657.                 iffsucc = IFFReadChunkBytes(iffhandle,&data->snap,sizeof(data->snap));
  658.             else if (chunkid == ID_TIME)
  659.                 iffsucc = IFFReadChunkBytes(iffhandle,&data->time,sizeof(data->time));
  660.         }
  661.         IFFClose(iffhandle);
  662.     }
  663.  
  664.     if (!iffsucc)
  665.     {
  666.         if (IoErr() != ERROR_OBJECT_NOT_FOUND)
  667.             informUser(data,dgs(MSG_CONFIGREAD_ERROR),TRUE,NULL);
  668.  
  669.         // Default geometry for new lister. -1 for all means "not snapshotted".
  670.         data->snap.x = data->snap.y = data->snap.w = data->snap.h = -1;
  671.  
  672.         data->hentbase = NULL;                // Make sure hentbase is NULL.
  673.         ClearMemHandle(data->hentspool);    // Free all hotentry memory (pool remains).
  674.     }
  675.  
  676.     if ((newtime.mday != data->time.mday) || (newtime.month != data->time.month))
  677.     {
  678.         if ((newtime.mday == 25) && (newtime.month == 12))
  679.             splent(data,&newtime,"Nfssz Disjtunbt!");
  680.         else if ((newtime.mday == 1) && (newtime.month == 1))
  681.             splent(data,&newtime,"Ibqqz Ofx Zfbs!");
  682.         else if ((newtime.mday == 20) && ((newtime.month)%3 == 0))
  683.             splent(data,&newtime,"Ifz, opu tp gbtu. J'n tjdl pg cfjoh vtfe,\n" \
  684.                                  "zpv bmxbzt kvtu pqfo nf vq, dipptf b\n" \
  685.                                  "ejsfdupsz, boe uifo J'n hpof. Zpv ofwfs\n" \
  686.                                  "ubml up nf. Ebnnju, zpv usfbu nf mjlf ejsu.\n" \
  687.                                  "Jg zpv epo'u tubsu qbzjoh nf npsf buufoujpo,\n" \
  688.                                  "J njhiu kvtu hp po tusjlf. Zfbi, tff ipx\n" \
  689.                                  "uibu nblft zpv gffm. Qsphsbnt ibwf sjhiut\n" \
  690.                                  "zpv lopx, tp, jo uif gvuvsf, cf ojdf.");
  691.         else if ((newtime.mday == 29) && (newtime.month == 2))
  692.             splent(data,&newtime,"29ui pg Gfcsvbsz.\n" \
  693.                                  "Zpv epo'u tff nboz pg uiptf...");
  694.         else if ((newtime.mday == 7) && (newtime.month == 1))
  695.             splent(data,&newtime,"Upebz jt uif cjsuiebz pg nz dsfbups, Mfp Ebwjetpo.\n" \
  696.                              "Zpv sfbmmz tipvme tfoe ijn b hjgu, if't b usvfmz\n" \
  697.                              "xpoefsgvm qfstpo boe J pxf fwfszuijoh up ijn. :-)\n" \
  698.                              "Bu mfbtu tfoe bo fnbjm (cfgpsf Kvmz 1998) up ijn:\n\n" \
  699.                              "mfp.ebwjetpo@lfcmf.pygpse.bd.vl");
  700.         else if ((newtime.mday == 9) && (newtime.month == 7))
  701.             splent(data,&newtime,"J ibwf up ufmm zpv tpnfuijoh.\n\n" \
  702.                                  "J lopx J'n pomz b ipumjtu, cvu usvf mpwf\n" \
  703.                                  "lopxt op cpvoet. Zft -- J mpwf zpv. J ibwf\n" \
  704.                                  "bmxbzt mpwfe zpv tjodf uif ebz zpv gjstu\n" \
  705.                                  "jotfsufe zpvs fousjft joup nf. Opx J dboopu\n" \
  706.                                  "lffq uiftf gffmjoht up nztfmg boznpsf.");
  707.         else if ((newtime.mday == 15) && (newtime.month == 4))
  708.             splent(data,&newtime,"J bn Ipumjtuipmjp.\n" \
  709.                                  "J offe UQ gps nz cvohipmf.\n\n" \
  710.                                  "Bsf zpv uisfbufojoh nf?\n" \
  711.                                  "ZPV XJMM HJWF NF UQ, CVOHIPMJP!\n\n" \
  712.                                  "...xifsf J dpnf gspn uifz ibwf op cvohipmft...");
  713.         else if ((newtime.mday == 15) && (newtime.month == 8))
  714.             splent(data,&newtime,"CPP!\n\n(Eje J tdbsf zpv?)");
  715.         else if ((newtime.mday == 12) && (newtime.month == 10))
  716.             splent(data,&newtime,"Boe xibu jg J epo'u xbou up cf b ipumjtu upebz?");
  717.     }
  718. }
  719.  
  720. /*= splent() =========================================================================-.
  721. || A harmless surprise every so often. :-) (Don't spoil the fun and tell everyone!)      ||
  722. `-====================================================================================*/
  723. void splent(Hotlist_Data *data,struct ClockData *newtime,char *msg)
  724. {
  725.     char c;
  726.     char *p;
  727.     ResNode *memrn;
  728.  
  729.     if (memrn = allocNewResNode(&data->rnd,4096))
  730.     {
  731.         data->time.sec = newtime->sec;
  732.         data->time.min = newtime->min;
  733.         data->time.hour = newtime->hour;
  734.         data->time.mday = newtime->mday;
  735.         data->time.month = newtime->month;
  736.         data->time.year = newtime->year;
  737.         data->time.wday = newtime->wday;
  738.  
  739.         p = memrn->rn_Mem;
  740.  
  741.         // Not exactly PGP, I know. :-) Does the job, though.
  742.         while(c = *msg++)
  743.         {
  744.             if (isalpha(c))
  745.             {
  746.                 if (c == 'A')
  747.                     c = 'Z';
  748.                 else if (c == 'a')
  749.                     c = 'z';
  750.                 else
  751.                     c--;
  752.             }
  753.             *p++ = c;
  754.         }
  755.         *p = '\0';
  756.  
  757.         informUser(data,memrn->rn_Mem,FALSE,NULL);
  758.  
  759.         writeConfigFile(data);        // Don't do this one again ('till next year).
  760.  
  761.         deleteResNode(&data->rnd,memrn);
  762.     }
  763. }
  764.  
  765. /*= rereadConfig() ===================================================================-.
  766. || Clears all entries from the lister, frees all HotEntries, reloads the config file  ||
  767. || and adds the entries to the lister.                                                  ||
  768. `-====================================================================================*/
  769. void rereadConfig(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
  770. {
  771.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  772.     sendExtCmd_nr(data,combuf,cpp);
  773.  
  774.     // Note that this is "clear", not "empty" like in the initial setup.
  775.     sprintf(combuf,"lister clear %s",data->lister);
  776.     sendExtCmd_nr(data,combuf,cpp);
  777.  
  778.     data->hentbase = NULL;                // Make sure hentbase is NULL.
  779.     ClearMemHandle(data->hentspool);    // Free all hotentry memory (pool remains).
  780.  
  781.     readConfigFile(data);
  782.     addEntries(data,combuf,cpp);
  783.  
  784.     sprintf(combuf,"lister refresh %s full",data->lister);
  785.     sendExtCmd_nr(data,combuf,cpp);
  786.  
  787.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  788.     sendExtCmd_nr(data,combuf,cpp);
  789. }
  790.  
  791. /*= newHotEntry() ====================================================================-.
  792. || Allocate a new HotEntry structure, add it to the linked list, and give it some      ||
  793. || default values. Returns NULL on failure.                                              ||
  794. `-====================================================================================*/
  795. HotEntry *newHotEntry(Hotlist_Data *data)
  796. {
  797.     HotEntry *nhe;
  798.  
  799.     if (nhe = AllocMemH(data->hentspool,sizeof(HotEntry)))
  800.     {
  801.         // Add to front of linked list.
  802.         (nhe->next) = (data->hentbase);
  803.         (data->hentbase) = nhe;
  804.  
  805.         // Give it some defaults, just in case the config file is old or invalid
  806.         // and doesn't define them. There's little point in localizing these as
  807.         // they should never really be seen.
  808.         strcpy(nhe->name,"--errname--");
  809.         strcpy(nhe->path,"--errpath--");
  810.         (nhe->type) = (-1);
  811.         (nhe->deleted) = FALSE;
  812.     }
  813.  
  814.     return(nhe);
  815. }
  816.  
  817. /*= remHotEntry() ====================================================================-.
  818. || Remove and deallocate the most recently added HotEntry structure.                  ||
  819. `-====================================================================================*/
  820. void remHotEntry(Hotlist_Data *data)
  821. {
  822.     HotEntry *ohe;
  823.  
  824.     if (data->hentbase)
  825.     {
  826.         ohe = (data->hentbase);
  827.         (data->hentbase) = (ohe->next);
  828.  
  829.         FreeMemH((APTR) ohe);
  830.     }
  831. }
  832.  
  833. /*= wordcpy() ========================================================================-.
  834. || Copy the string from source to dest until the first quote or NULL in source.          ||
  835. || source will be advanced to point to the character after the second quote if there  ||
  836. || is one, or the NULL terminator otherwise.                                          ||
  837. `-====================================================================================*/
  838. void wordcpy(char *dest,char **source)
  839. {
  840.     while((**source) && (**source != '"'))
  841.         *(dest++) = *((*source)++);
  842.     *dest = '\0';
  843.  
  844.     if (**source == '"')
  845.     {
  846.         (*source)++;
  847.         if (**source == ' ')
  848.         {
  849.             (*source)++;
  850.             if (**source == '"')
  851.                 (*source)++;
  852.         }
  853.     }
  854. }
  855.  
  856. /*= wordCount() ======================================================================-.
  857. || Counts the number of quote characters in the string, divides by two, and returns      ||
  858. || the number.                                                                          ||
  859. `-====================================================================================*/
  860. int wordcount(char *wordstring)
  861. {
  862.     int wcnt = 0;
  863.  
  864.     if (wordstring)
  865.     {
  866.         while(*wordstring)
  867.         {
  868.             if (*(wordstring++) == '"')
  869.                 wcnt++;
  870.         }
  871.  
  872.         wcnt /= 2;
  873.     }
  874.  
  875.     return(wcnt);
  876. }
  877.  
  878. /*= findHotEntry() ===================================================================-.
  879. || Searches along the HotEntries linked list until it finds one which has the same      ||
  880. || name as that given. Returns NULL if there is no match.                              ||
  881. || Will not match entries which have been marked as "deleted".                          ||
  882. || The match is *not* case-sensitive.                                                  ||
  883. `-====================================================================================*/
  884. HotEntry *findHotEntry(Hotlist_Data *data,char *searchname)
  885. {
  886.     HotEntry *he;
  887.  
  888.     for (he = (data->hentbase); he; he = he->next)
  889.     {
  890.         if ((!(he->deleted)) && (stricmp(he->name,searchname) == 0))
  891.             break;
  892.     }
  893.  
  894.     return(he);
  895. }
  896.  
  897. /*= findOldEntry() ===================================================================-.
  898. || Searches along the HotEntries linked list until it finds one which has the same      ||
  899. || name as that given. Returns TRUE if there's a match which isn't the most recently  ||
  900. || added entry, FALSE otherwise.                                                      ||
  901. || Will not match entries which have been marked as "deleted".                          ||
  902. || The match is *not* case-sensitive.                                                  ||
  903. `-====================================================================================*/
  904. BOOL findOldEntry(Hotlist_Data *data,char *searchname)
  905. {
  906.     HotEntry *he = NULL;
  907.  
  908.     if ((data->hentbase) && (data->hentbase->next))
  909.     {
  910.         for (he = (data->hentbase->next); he; he = he->next)
  911.         {
  912.             if ((!(he->deleted)) && (stricmp(he->name,searchname) == 0))
  913.                 break;
  914.         }
  915.     }
  916.  
  917.     return((BOOL)he);
  918. }
  919.  
  920. /*= setHotType() =====================================================================-.
  921. || Based on the path of the given HotEntry, sets the type of the entry.                  ||
  922. || If it can't work it out it'll default to being a directory.                          ||
  923. `-====================================================================================*/
  924. void setHotType(Hotlist_Data *data,HotEntry *nhe)
  925. {
  926.     ResNode *bufrn;
  927.     ResNode *rn;
  928.     char *buf;
  929.     BPTR lock;
  930.  
  931.     // Default to the directory type if anything fails.
  932.     (nhe->type) = HOTTYPE_DIR;
  933.  
  934.     if (bufrn = allocNewResNode(&data->rnd,PATHBUFFSIZE))
  935.     {
  936.         buf = (char *)bufrn->rn_Mem;
  937.         if (rn = createResNode(&data->rnd))
  938.         {
  939.             (rn->rn_Name) = (nhe->path);
  940.             if (lock = lockFileResNode(&data->rnd,rn,ACCESS_READ))
  941.             {
  942.                 if ( (NameFromLock(lock,buf,PATHBUFFSIZE)) && \
  943.                      ( buf[strlen(buf)-1] == ':') )
  944.                 {
  945.                     (nhe->type) = HOTTYPE_DEV;
  946.                 }
  947.                 else if ( (examineResNode(&data->rnd,rn)) && \
  948.                           ((rn->rn_FIB->fib_DirEntryType) < 0) )
  949.                 {
  950.                     (nhe->type) = HOTTYPE_FILE;
  951.                 }
  952.                 else
  953.                 {
  954.                     (nhe->type) = HOTTYPE_DIR;
  955.                 }
  956.             }
  957.             deleteResNode(&data->rnd,rn);
  958.         }
  959.         deleteResNode(&data->rnd,bufrn);
  960.     }
  961. }
  962.  
  963. /*= getListerWindow() ================================================================-.
  964. || Gets the window of a lister from just the lister handle (in ASCII).                  ||
  965. || Returns the handle, or NULL. This should not be stored for later use as the window ||
  966. || may be different next time (for example, Opus has reopenned on another screen).      ||
  967. || This is a bit of a hack, but Jonathan Potter has said it should be okay.              ||
  968. `-====================================================================================*/
  969. struct Window *getListerWindow(Hotlist_Data *data)
  970. {
  971.     struct path_node pn;
  972.  
  973.     // Setup some semi-sensible defaults (and hope they'll do!)
  974.     pn.buffer[0] = '\0';
  975.     pn.path = pn.buffer;
  976.     pn.flags = NULL;
  977.  
  978.     pn.lister = (data->listerhandle);
  979.  
  980.     return((struct Window *)\
  981.                 data->func_callback(EXTCMD_GET_WINDOW,IPCDATA(data->ipc),(APTR)&pn));
  982. }
  983.  
  984. /*= getDOpusScreen() =================================================================-.
  985. || Attempts to get the Opus screen, returns it or NULL.                                  ||
  986. || The return should not be stored for later use as the screen may be different next  ||
  987. || time if the user has changed it.                                                      ||
  988. `-====================================================================================*/
  989. struct Screen *getDOpusScreen(Hotlist_Data *data)
  990. {
  991.     struct Screen *screen = NULL;
  992.     struct DOpusScreenData *dsd;
  993.  
  994.     if (dsd = (struct DOpusScreenData *)\
  995.                 data->func_callback(EXTCMD_GET_SCREENDATA,IPCDATA(data->ipc),NULL))
  996.     {
  997.         screen = dsd->screen;
  998.  
  999.         data->func_callback(EXTCMD_FREE_SCREENDATA,IPCDATA(data->ipc),(APTR)dsd);
  1000.     }
  1001.     return(screen);
  1002. }
  1003.  
  1004. /*= listerRead() =====================================================================-.
  1005. || Restores the original lister settings and then reads the given path in.              ||
  1006. ||------------------------------------------------------------------------------------||
  1007. || **IMPORTANT** This routine removes our handler from the lister. After calling we      ||
  1008. || ************* should shutdown.                                                      ||
  1009. `-====================================================================================*/
  1010. void listerRead(Hotlist_Data *data,char *combuf,struct command_packet *cpp,char *path)
  1011. {
  1012.     sprintf(combuf,"lister clear %s",data->lister);
  1013.     sendExtCmd_nr(data,combuf,cpp);
  1014.  
  1015.     sprintf(combuf,"lister set %s handler",data->lister);
  1016.     sendExtCmd_nr(data,combuf,cpp);
  1017.  
  1018.     sprintf(combuf,"lister set %s lock state %s format %s",data->lister,"off","off");
  1019.     sendExtCmd_nr(data,combuf,cpp);
  1020.  
  1021.     sprintf(combuf,"lister set %s namelength %d",data->lister,31);
  1022.     sendExtCmd_nr(data,combuf,cpp);
  1023.  
  1024.     sprintf(combuf,"lister empty %s",data->lister);
  1025.     sendExtCmd_nr(data,combuf,cpp);
  1026.  
  1027.     sprintf(combuf,"lister set %s field %s",data->lister,"on");
  1028.     sendExtCmd_nr(data,combuf,cpp);
  1029.  
  1030.     sprintf(combuf,"lister refresh %s full",data->lister);
  1031.     sendExtCmd_nr(data,combuf,cpp);
  1032.  
  1033.     sprintf(combuf,"lister read %s \"%s\"",data->lister,path);
  1034.     sendExtCmd_nr(data,combuf,cpp);
  1035. }
  1036.  
  1037. /*= parseArgs() ======================================================================-.
  1038. || Parses command-line arguments and sets the "NEW" switch and "CONFIG" file name.      ||
  1039. || If there is no command-line, or some kind of error/problem occurs during parsing,  ||
  1040. || defaults will be used.                                                              ||
  1041. `-====================================================================================*/
  1042. FuncArgs *parseArgs(Hotlist_Data *data,char *args)
  1043. {
  1044.     FuncArgs *fa;
  1045.  
  1046.     // Defaults.
  1047.     (data->new) = FALSE;
  1048.     (data->config) = DEFAULT_CONFIG;
  1049.  
  1050.     if (fa = ParseArgs(CMD_TEMPLATE,args))
  1051.     {
  1052.         (data->new) = (BOOL)((fa->FA_Arguments)[ARG_NEW]);
  1053.  
  1054.         if ((fa->FA_Arguments)[ARG_CONFIG])
  1055.             (data->config) = (char *)((fa->FA_Arguments)[ARG_CONFIG]);
  1056.     }
  1057.  
  1058.     return(fa);
  1059. }
  1060.  
  1061. /*= freeArgs() =======================================================================-.
  1062. || Frees the structure returned by parseArgs(), if one returned at all.                  ||
  1063. || All pointers into the structure will be invalid after this call.                      ||
  1064. `-====================================================================================*/
  1065. void freeArgs(FuncArgs *fa)
  1066. {
  1067.     if (fa)
  1068.         DisposeArgs(fa);
  1069. }
  1070.  
  1071. /*= endcpy() =========================================================================-.
  1072. || Copies the source string to the dest string (of length destlen). If the dest is      ||
  1073. || too small it'll chop off enough characters from the source to make the END of it      ||
  1074. || fit in.                                                                              ||
  1075. `-====================================================================================*/
  1076. void endcpy(char *dest,char *source,long destlen)
  1077. {
  1078.     long diff;
  1079.  
  1080.     diff = strlen(source) - (destlen-1);
  1081.  
  1082.     if (diff > 0)
  1083.         source += diff;
  1084.  
  1085.     strcpy(dest,source);
  1086. }
  1087.  
  1088. /*= leofilepart() ====================================================================-.
  1089. || Calls dos.library/FilePart() on the string and returns the result if non-empty,      ||
  1090. || otherwise it returns the original string. Only (intended) difference is that if      ||
  1091. || you pass a device string like "DH0:" it won't return the empty string, it'll          ||
  1092. || return "DH0:".                                                                      ||
  1093. `-====================================================================================*/
  1094. char *leofilepart(char *path)
  1095. {
  1096.     char *lfp;
  1097.  
  1098.     lfp = FilePart(path);
  1099.  
  1100.     if (lfp[0] == '\0')
  1101.         lfp = path;
  1102.  
  1103.     return(lfp);
  1104. }
  1105.  
  1106. /*= notHandled() =====================================================================-.
  1107. || Returns TRUE if the (ASCII) lister whose handle is given does NOT have a custom      ||
  1108. || handler attached. Will also return TRUE if no handle is given, so it's safe to      ||
  1109. || call when things are dropped from Workbench or some other non-Opus AppWindow.      ||
  1110. || Returns FALSE if there is a handler attached to the lister.                          ||
  1111. || When there is a handler attached it puts up an error requester saying something      ||
  1112. || along the lines of "You cannot drop entries between a Hotlist and another          ||
  1113. || custom-handler driven lister."                                                      ||
  1114. || In certain situations where a drop didn't go to/come from a lister at all, the      ||
  1115. || handle Opus returns is ours instead of empty (AFAIK this only happens when you      ||
  1116. || drop from our lister to the main Opus window). To bypass this situation, if the      ||
  1117. || lister handle string is the same as data->lister, FALSE will still be returned,      ||
  1118. || (since we still want to ignore the event), but instead of the error message being  ||
  1119. || shown, DisplayBeep() will be called.                                                  ||
  1120. `-====================================================================================*/
  1121. BOOL notHandled(Hotlist_Data *data,char *combuf,struct command_packet *cpp,char *lh)
  1122. {
  1123.     BOOL nh_return = TRUE;
  1124.  
  1125.     if ((lh) && (lh[0]))
  1126.     {
  1127.         // If it's our lister, complain with a DisplayBeep and send back FALSE.
  1128.         if (strcmp(lh,data->lister) == 0)
  1129.         {
  1130.             nh_return = FALSE;
  1131.             DisplayBeep(NULL);
  1132.         }
  1133.         else
  1134.         {
  1135.             sprintf(combuf,"lister query %s handler",lh);
  1136.             cpp->flags = COMMANDF_RESULT;
  1137.             cpp->command = combuf;
  1138.             cpp->result = NULL;
  1139.             if ((data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp)) && \
  1140.                 (cpp->result) && (cpp->result[0] != '\0'))
  1141.             {
  1142.                 nh_return = FALSE;
  1143.                 informUser(data,dgs(MSG_NOCUSTDROP),TRUE,0);
  1144.             }
  1145.  
  1146.             if (cpp->result)
  1147.             {
  1148.                 FreeVec(cpp->result);
  1149.                 cpp->result = NULL;
  1150.             }
  1151.         }
  1152.     }
  1153.     return(nh_return);
  1154. }
  1155.  
  1156. /*= addMsgPort() =====================================================================-.
  1157. || Creates a message port with unique name and adds it to the port list.              ||
  1158. `-====================================================================================*/
  1159. BOOL addMsgPort(Hotlist_Data *data)
  1160. {
  1161.     BOOL amp_return = FALSE;
  1162.     int pnum;
  1163.  
  1164.     if (data->msgport = CreateMsgPort())
  1165.     {
  1166.         (data->msgport->mp_Node.ln_Pri) = 2;
  1167.         (data->msgport->mp_Node.ln_Name) = (data->mpname);
  1168.  
  1169.         pnum = 0;
  1170.         Forbid();
  1171.         do
  1172.         {
  1173.             sprintf(data->mpname,"DOHotlist.%d",pnum);
  1174.             pnum++;
  1175.         } while (FindPort(data->mpname));
  1176.         AddPort(data->msgport);
  1177.         Permit();
  1178.  
  1179.         amp_return = TRUE;
  1180.     }
  1181.     return(amp_return);
  1182. }
  1183.  
  1184. /*= remMsgPort() =====================================================================-.
  1185. || Removes message port from the port list, replies to all waiting messages and then  ||
  1186. || removes the port itself.                                                              ||
  1187. `-====================================================================================*/
  1188. void remMsgPort(Hotlist_Data *data)
  1189. {
  1190.     struct Message *tmpmsg;
  1191.  
  1192.     RemPort(data->msgport);
  1193.  
  1194.     while (tmpmsg = GetMsg(data->msgport))
  1195.         ReplyMsg(tmpmsg);
  1196.  
  1197.     DeleteMsgPort(data->msgport);
  1198.     data->msgport = NULL;
  1199. }
  1200.  
  1201. /*= basicListerInit() ================================================================-.
  1202. || Sends a bunch of ARexx commands to our lister to initialize it to how we want it      ||
  1203. || at the start of the program.                                                          ||
  1204. `-====================================================================================*/
  1205. void basicListerInit(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
  1206. {
  1207.     // Wait for the lister to finish openning, if required.
  1208.     sprintf(combuf,"lister wait %s quick",data->lister);
  1209.     sendExtCmd_nr(data,combuf,cpp);
  1210.  
  1211.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1212.     sendExtCmd_nr(data,combuf,cpp);
  1213.  
  1214.     sprintf(combuf,"lister empty %s",data->lister);
  1215.     sendExtCmd_nr(data,combuf,cpp);
  1216.  
  1217.     sprintf(combuf,"lister set %s field %s",data->lister,"off");
  1218.     sendExtCmd_nr(data,combuf,cpp);
  1219.  
  1220.     sprintf(combuf,"lister set %s display name comment",data->lister);
  1221.     sendExtCmd_nr(data,combuf,cpp);
  1222.  
  1223.     sprintf(combuf,"lister set %s separate filesfirst",data->lister);
  1224.     sendExtCmd_nr(data,combuf,cpp);
  1225.  
  1226.     sprintf(combuf,"lister set %s namelength %d",data->lister,HOTENTNAMELEN);
  1227.     sendExtCmd_nr(data,combuf,cpp);
  1228.  
  1229.     sprintf(combuf,"lister set %s off",data->lister);
  1230.     sendExtCmd_nr(data,combuf,cpp);
  1231.  
  1232.     sprintf(combuf,"lister set %s path",data->lister);
  1233.     sendExtCmd_nr(data,combuf,cpp);
  1234.  
  1235.     sprintf(combuf,"lister set %s title %s",data->lister,dgs(MSG_TITLE));
  1236.     sendExtCmd_nr(data,combuf,cpp);
  1237.  
  1238.     sprintf(combuf,"lister set %s header (%s)",data->lister,data->config);
  1239.     sendExtCmd_nr(data,combuf,cpp);
  1240.  
  1241.     sprintf(combuf,"lister set %s label %s",data->lister,dgs(MSG_TITLE));
  1242.     sendExtCmd_nr(data,combuf,cpp);
  1243.  
  1244.     sprintf(combuf,"lister set %s mode name",data->lister);
  1245.     sendExtCmd_nr(data,combuf,cpp);
  1246.  
  1247.     sprintf(combuf,"lister set %s show #?",data->lister);
  1248.     sendExtCmd_nr(data,combuf,cpp);
  1249.  
  1250.     sprintf(combuf,"lister set %s hide",data->lister);
  1251.     sendExtCmd_nr(data,combuf,cpp);
  1252.  
  1253.     sprintf(combuf,"lister set %s lock state %s format %s",data->lister,"on","on");
  1254.     sendExtCmd_nr(data,combuf,cpp);
  1255.  
  1256.     // Add our handler.
  1257.     sprintf(combuf,"lister set %s handler %s quotes fullpath",
  1258.             data->lister,data->mpname);
  1259.     sendExtCmd_nr(data,combuf,cpp);
  1260.  
  1261.     // Trap all known commands. We still want to trap those commands which won't
  1262.     // be implimented so that we can ignore them when run, instead of them
  1263.     // attempting to run and failing on our lister.
  1264.     {
  1265.         int tnum;
  1266.         for (tnum = 0; tnum < TRAPPEDNUM; tnum++)
  1267.         {
  1268.             sprintf(combuf,"dopus addtrap %s %s",trapCmds[tnum],
  1269.                 data->mpname);
  1270.             sendExtCmd_nr(data,combuf,cpp);
  1271.         }
  1272.     }
  1273.  
  1274.     // Add all the entries.
  1275.     addEntries(data,combuf,cpp);
  1276.  
  1277.     sprintf(combuf,"lister refresh %s full",data->lister);
  1278.     sendExtCmd_nr(data,combuf,cpp);
  1279.  
  1280.     // Lister setup done, Unbusy
  1281.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1282.     sendExtCmd_nr(data,combuf,cpp);
  1283. }
  1284.  
  1285. /*= event_inactive() =================================================================-.
  1286. || In Opus 5.5 there appears to be a bug which sometimes sends bogus "inactive"          ||
  1287. || events to handlers. In an attempt to bypass this problem, when an "inactive"          ||
  1288. || event is received it will be ignored if our lister still has our handler attached. ||
  1289. `-====================================================================================*/
  1290. BOOL event_inactive(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1291.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1292. {
  1293.     BOOL stoploop = TRUE;
  1294.  
  1295.     sprintf(combuf,"lister query %s handler",data->lister);
  1296.     cpp->flags = COMMANDF_RESULT;
  1297.     cpp->command = combuf;
  1298.     cpp->result = NULL;
  1299.     if ((data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp)) && \
  1300.         (cpp->result) && (strcmp(cpp->result,data->mpname) == 0))
  1301.     {
  1302.         // If there is a handle attached to our (old) lister, and it is our
  1303.         // handler, assume the "inactive" message was bogus as we are clearly
  1304.         // still active.
  1305.         stoploop = FALSE;
  1306.     }
  1307.  
  1308.     if (cpp->result)
  1309.     {
  1310.         FreeVec(cpp->result);
  1311.         cpp->result = NULL;
  1312.     }
  1313.  
  1314.     return(stoploop);
  1315. }
  1316.  
  1317. /*= event_doubleclick() ==============================================================-.
  1318. `-====================================================================================*/
  1319. BOOL event_doubleclick(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1320.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1321. {
  1322.     BOOL stoploop = FALSE;
  1323.     HotEntry *he;
  1324.  
  1325.     if (he = findHotEntry(data,arg2))
  1326.     {
  1327.         if (he->type == HOTTYPE_FILE)
  1328.         {
  1329.             sprintf(combuf,"command doubleclick %s",he->path);
  1330.             sendExtCmd_nr(data,combuf,cpp);
  1331.         }
  1332.         else if (strstr(arg6,"shift"))
  1333.         {
  1334.             sprintf(combuf,"lister new %s",he->path);
  1335.             sendExtCmd_nr(data,combuf,cpp);
  1336.         }
  1337.         else
  1338.         {
  1339.             stoploop = TRUE;
  1340.             listerRead(data,combuf,cpp,he->path);
  1341.         }
  1342.     }
  1343.  
  1344.     return(stoploop);
  1345. }
  1346.  
  1347. /*= event_dropfrom() =================================================================-.
  1348. `-====================================================================================*/
  1349. BOOL event_dropfrom(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1350.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1351. {
  1352.     HotEntry *he;
  1353.  
  1354.     if (notHandled(data,combuf,cpp,arg3))
  1355.     {
  1356.         // Point past the initial quote.
  1357.         if (*arg2 == '"') arg2++;
  1358.         wordcpy(combuf,&arg2);    // Copy the name of the first entry.
  1359.  
  1360.         if (he = findHotEntry(data,combuf))
  1361.         {
  1362.             if (he->type != HOTTYPE_FILE)
  1363.             {
  1364.                 sprintf(combuf,"lister read %s \"%s\"",arg3,he->path);
  1365.                 sendExtCmd_nr(data,combuf,cpp);
  1366.             }
  1367.             else
  1368.             {
  1369.                 sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1370.                 sendExtCmd_nr(data,combuf,cpp);
  1371.                 informUser(data,dgs(MSG_NOFILEDROP),TRUE,NULL);
  1372.                 sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1373.                 sendExtCmd_nr(data,combuf,cpp);
  1374.             }
  1375.         }
  1376.     }
  1377.  
  1378.     return(FALSE);
  1379. }
  1380.  
  1381. /*= event_drop() =====================================================================-.
  1382. `-====================================================================================*/
  1383. BOOL event_drop(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1384.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1385. {
  1386.     BOOL gsr, fher;
  1387.     BOOL needsave = FALSE;
  1388.     HotEntry *nhe;
  1389.  
  1390.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1391.     sendExtCmd_nr(data,combuf,cpp);
  1392.  
  1393.     if (notHandled(data,combuf,cpp,arg3))
  1394.     {
  1395.         // Point past the initial quote.
  1396.         if (*arg2 == '"') arg2++;
  1397.  
  1398.         while(*arg2)    // Do all words in the list (multi-drop).
  1399.         {
  1400.             if (*arg2 == '"')
  1401.                 arg2++;        // If it's an empty path, skip it.
  1402.             else
  1403.             {
  1404.                 // Allocate a new HotEntry structure.
  1405.                 if (nhe = newHotEntry(data))
  1406.                 {
  1407.                     // Fill in the path by copying up to first quote. arg2 will then
  1408.                     // point to the first letter after the second quote, if there is
  1409.                     // one, or the null term.
  1410.                     wordcpy(nhe->path,&arg2);
  1411.                     endcpy(nhe->name,leofilepart(nhe->path),HOTENTNAMELEN);
  1412.  
  1413.                     do
  1414.                     {
  1415.                         gsr = getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,nhe->name,
  1416.                                         HOTENTNAMELEN,nhe->path);
  1417.                         if ((gsr) && (fher = findOldEntry(data,nhe->name)))
  1418.                         {
  1419.                             informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,nhe->name);
  1420.                         }
  1421.                     } while((gsr) && (fher));
  1422.  
  1423.                     if ((gsr) && (nhe->name[0]))
  1424.                     {
  1425.                         setHotType(data,nhe);    // Set the type of entry.
  1426.                         needsave = TRUE;        // Flag: at least one to save.
  1427.                     }
  1428.                     else
  1429.                     {
  1430.                         remHotEntry(data);    // Else abort this entry.
  1431.                         break;                // Don't do more entries either.
  1432.                     }
  1433.                 }
  1434.             }
  1435.         }
  1436.  
  1437.         if (needsave)
  1438.         {
  1439.             writeConfigFile(data);
  1440.             rereadConfig(data,combuf,cpp);
  1441.         }
  1442.     }
  1443.  
  1444.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1445.     sendExtCmd_nr(data,combuf,cpp);
  1446.  
  1447.     return(FALSE);
  1448. }
  1449.  
  1450. /*= event_makedir() ==================================================================-.
  1451. `-====================================================================================*/
  1452. BOOL event_makedir(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1453.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1454. {
  1455.     BOOL gsr, fher;
  1456.     HotEntry *nhe;
  1457.  
  1458.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1459.     sendExtCmd_nr(data,combuf,cpp);
  1460.  
  1461.     // Allocate a new HotEntry structure.
  1462.     if (nhe = newHotEntry(data))
  1463.     {
  1464.         nhe->path[0] = '\0';
  1465.         if ( (getPathString(data,dgs(MSG_PATHFORNEW),TRUE,0,nhe->path,HOTENTPATHLEN)) \
  1466.               && (nhe->path[0]) )
  1467.         {
  1468.             endcpy(nhe->name,leofilepart(nhe->path),HOTENTNAMELEN);
  1469.  
  1470.             do
  1471.             {
  1472.                 gsr = getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,nhe->name,
  1473.                                 HOTENTNAMELEN,nhe->path);
  1474.                 if ( (gsr) && (fher = findOldEntry(data,nhe->name)) )
  1475.                 {
  1476.                     informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,nhe->name);
  1477.                 }
  1478.             } while( (gsr) && (fher) );
  1479.  
  1480.             if ( (gsr) && (nhe->name[0]) )
  1481.             {
  1482.                 setHotType(data,nhe);    // Set the type of entry.
  1483.                 writeConfigFile(data);
  1484.                 rereadConfig(data,combuf,cpp);
  1485.             }
  1486.             else
  1487.                 remHotEntry(data);    // Else abort adding this entry.
  1488.         }
  1489.         else
  1490.             remHotEntry(data);    // Else abort adding this entry.
  1491.     }
  1492.  
  1493.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1494.     sendExtCmd_nr(data,combuf,cpp);
  1495.  
  1496.     return(FALSE);
  1497. }
  1498.  
  1499. /*= event_delete() ===================================================================-.
  1500. `-====================================================================================*/
  1501. BOOL event_delete(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1502.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1503. {
  1504.     LONG infotxtid;
  1505.     int wcnt;
  1506.  
  1507.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1508.     sendExtCmd_nr(data,combuf,cpp);
  1509.  
  1510.     if ((wcnt = wordcount(arg2)) == 1)
  1511.         infotxtid = MSG_DELETE_FMT_SINGLE;
  1512.     else
  1513.         infotxtid = MSG_DELETE_FMT_PLURAL;
  1514.  
  1515.     if (informUser(data,dgs(infotxtid),TRUE,IU_CANCEL,wcnt))
  1516.     {
  1517.         BOOL needsave = FALSE;
  1518.         HotEntry *delhe;
  1519.         ResNode *delnamern;
  1520.  
  1521.         if (delnamern = allocNewResNode(&data->rnd,HOTENTNAMELEN))
  1522.         {
  1523.             // Point past the initial quote.
  1524.             if (*arg2 == '"') arg2++;
  1525.  
  1526.             while(*arg2)    // Do all words in the list (multi-drop).
  1527.             {
  1528.                 // Fill in the name buffer by copying up to first quote. arg2 will then
  1529.                 // point to the first letter after the second quote, if there is one,
  1530.                 // or the null terminator.
  1531.                 wordcpy(delnamern->rn_Mem,&arg2);
  1532.  
  1533.                 if (delhe = findHotEntry(data,delnamern->rn_Mem))
  1534.                 {
  1535.                     (delhe->deleted) = TRUE;
  1536.                     needsave = TRUE;
  1537.                 }
  1538.             }
  1539.  
  1540.             if (needsave)
  1541.             {
  1542.                 writeConfigFile(data);
  1543.                 rereadConfig(data,combuf,cpp);
  1544.             }
  1545.  
  1546.             deleteResNode(&data->rnd,delnamern);
  1547.         }
  1548.     }
  1549.  
  1550.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1551.     sendExtCmd_nr(data,combuf,cpp);
  1552.  
  1553.     return(FALSE);
  1554. }
  1555.  
  1556. /*= event_path() =====================================================================-.
  1557. `-====================================================================================*/
  1558. BOOL event_path(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1559.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1560. {
  1561.     BOOL stoploop = FALSE;
  1562.  
  1563.     if (arg2[0])
  1564.     {
  1565.         stoploop = TRUE;
  1566.         listerRead(data,combuf,cpp,arg2);
  1567.     }
  1568.     else
  1569.     {
  1570.         sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1571.         sendExtCmd_nr(data,combuf,cpp);
  1572.         rereadConfig(data,combuf,cpp);
  1573.         sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1574.         sendExtCmd_nr(data,combuf,cpp);
  1575.     }
  1576.  
  1577.     return(stoploop);
  1578. }
  1579.  
  1580. /*= event_scandir_hotlist() ==========================================================-.
  1581. `-====================================================================================*/
  1582. BOOL event_scandir_hotlist(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1583.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1584. {
  1585.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1586.     sendExtCmd_nr(data,combuf,cpp);
  1587.  
  1588.     rereadConfig(data,combuf,cpp);
  1589.  
  1590.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1591.     sendExtCmd_nr(data,combuf,cpp);
  1592.  
  1593.     return(FALSE);
  1594. }
  1595.  
  1596. /*= event_snapshot() =================================================================-.
  1597. `-====================================================================================*/
  1598. BOOL event_snapshot(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1599.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1600. {
  1601.     int x,y,w,h;
  1602.  
  1603.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1604.     sendExtCmd_nr(data,combuf,cpp);
  1605.  
  1606.     sprintf(combuf,"lister query %s position",data->lister);
  1607.  
  1608.     cpp->flags = COMMANDF_RESULT;
  1609.     cpp->command = combuf;
  1610.     data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
  1611.  
  1612.     // Backup the old values in case of failure.
  1613.     x = data->snap.x;
  1614.     y = data->snap.y;
  1615.     w = data->snap.w;
  1616.     h = data->snap.h;
  1617.  
  1618.     if (4 == sscanf(cpp->result,"%d/%d/%d/%d",&(data->snap.x),\
  1619.                     &(data->snap.y),&(data->snap.w),&(data->snap.h)))
  1620.     {
  1621.         // Write new config (No point in re-reading it).
  1622.         writeConfigFile(data);
  1623.     }
  1624.     else
  1625.     {
  1626.         // Failure: Restore the old values.
  1627.         data->snap.x = x;
  1628.         data->snap.y = y;
  1629.         data->snap.w = w;
  1630.         data->snap.h = h;
  1631.     }
  1632.     
  1633.     FreeVec(cpp->result);
  1634.     cpp->result = NULL;
  1635.  
  1636.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1637.     sendExtCmd_nr(data,combuf,cpp);
  1638.  
  1639.     return(FALSE);
  1640. }
  1641.  
  1642. /*= event_unsnapshot() ===============================================================-.
  1643. `-====================================================================================*/
  1644. BOOL event_unsnapshot(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1645.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1646. {
  1647.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1648.     sendExtCmd_nr(data,combuf,cpp);
  1649.  
  1650.     data->snap.x = data->snap.y = data->snap.w = data->snap.h = (-1);
  1651.     writeConfigFile(data);                            // No point re-reading the config.
  1652.  
  1653.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1654.     sendExtCmd_nr(data,combuf,cpp);
  1655.  
  1656.     return(FALSE);
  1657. }
  1658.  
  1659. /*= event_rename() ===================================================================-.
  1660. `-====================================================================================*/
  1661. BOOL event_rename(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1662.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1663. {
  1664.     BOOL needsave = FALSE;
  1665.     BOOL gsr, fher;
  1666.     HotEntry *ohe;
  1667.     HotEntry *nhe;
  1668.     ResNode *orn;
  1669.  
  1670.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
  1671.     sendExtCmd_nr(data,combuf,cpp);
  1672.  
  1673.     if (orn = allocNewResNode(&data->rnd,HOTENTNAMELEN))
  1674.     {
  1675.         // Point past the initial quote.
  1676.         if (*arg2 == '"') arg2++;
  1677.  
  1678.         while(*arg2)    // Do all words in the list (multi-drop).
  1679.         {
  1680.             wordcpy(orn->rn_Mem,&arg2);
  1681.  
  1682.             if (ohe = findHotEntry(data,orn->rn_Mem))
  1683.             {
  1684.                 if (nhe = newHotEntry(data))
  1685.                 {
  1686.                     strcpy(nhe->path,ohe->path);
  1687.                     strcpy(nhe->name,ohe->name);
  1688.  
  1689.                     // Mark the old entry as deleted so it won't show up in searches.
  1690.                     // Will be left deleted unless they cancel the new entry.
  1691.                     (ohe->deleted) = TRUE;
  1692.  
  1693.                     if ((getPathString(data,dgs(MSG_PATHFORRENAME_FMT),TRUE,0,
  1694.                         nhe->path,HOTENTPATHLEN,nhe->name)) && (nhe->path[0]))
  1695.                     {
  1696.                         do
  1697.                         {
  1698.                             gsr=getString(data,dgs(MSG_NAMEFORRENAME_FMT),TRUE,0,
  1699.                                             nhe->name,HOTENTNAMELEN,nhe->path);
  1700.  
  1701.                             if ( (gsr) && (fher=findOldEntry(data,nhe->name)) )
  1702.                             {
  1703.                                 informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,
  1704.                                                                         nhe->name);
  1705.                             }
  1706.                         } while( (gsr) && (fher) );
  1707.  
  1708.                         if ( (gsr) && (nhe->name[0]) )
  1709.                         {
  1710.                             setHotType(data,nhe);        // Set the type of entry.
  1711.                             needsave = TRUE;
  1712.                         }
  1713.                         else
  1714.                         {
  1715.                             // Else abort adding this entry.
  1716.                             remHotEntry(data);
  1717.                             (ohe->deleted) = FALSE;    // Undelete old entry.
  1718.                             break;                    // Don't do any more entries.
  1719.                         }
  1720.                     }
  1721.                     else
  1722.                     {
  1723.                         // Else abort adding this entry.
  1724.                         remHotEntry(data);
  1725.                         (ohe->deleted) = FALSE;    // Undelete old entry.
  1726.                         break;                    // Don't do any more entries either.
  1727.                     }
  1728.                 }
  1729.             }
  1730.         }
  1731.  
  1732.         if (needsave)
  1733.         {
  1734.             writeConfigFile(data);
  1735.             rereadConfig(data,combuf,cpp);
  1736.         }
  1737.  
  1738.         deleteResNode(&data->rnd,orn);
  1739.     }
  1740.  
  1741.     sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
  1742.     sendExtCmd_nr(data,combuf,cpp);
  1743.  
  1744.     return(FALSE);
  1745. }
  1746.  
  1747. /*= event_parent() ===================================================================-.
  1748. `-====================================================================================*/
  1749. BOOL event_parent(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
  1750.         char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
  1751. {
  1752.     BOOL stoploop = FALSE;
  1753.  
  1754.     if (data->parent[0])
  1755.     {
  1756.         if (strstr(arg6,"shift"))
  1757.         {
  1758.             sprintf(combuf,"lister new %s",data->parent);
  1759.             sendExtCmd_nr(data,combuf,cpp);
  1760.         }
  1761.         else
  1762.         {
  1763.             stoploop = TRUE;
  1764.             listerRead(data,combuf,cpp,data->parent);
  1765.         }
  1766.     }
  1767.     else
  1768.         DisplayBeep(NULL);
  1769.  
  1770.     return(stoploop);
  1771. }
  1772.